﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ranorex.Core;
using Ranorex.Plugin;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace SophisAutoTestExt.Controls.MFC
{

    public enum MenuSelectionModifier
    {
        None,
        Ctrl,
        Shift,
        CtrlShift
    }

    public class MenuBar
    {
        //ranorex xpaths
        private const String CMenuBarContainerRxPath = "descendant::element[@controlid='59419' and @class='Afx:DockPane:400000:8:10003:10' and @instance='0']";
        private const String CMenuBarRxPath = "descendant::element[@accessiblename='Menu Bar']";
        private const String CSubMenuWindow = "descendant::form[@class='Afx:00400000:800:00010003:00000010:00000000']";

        //private properties
        private Ranorex.Form _form;
        private Element _menubarcontainer;
        private Element _menubarelement;
        private List<String> _topmenuitems;


        public MenuBar(Ranorex.Form sophisform)
        {
            _form = sophisform;
            _menubarcontainer = _form.FindSingle(CMenuBarContainerRxPath);
            _menubarelement = _menubarcontainer.FindSingle(CMenuBarRxPath);
            RawTextFlavor.Instance.ClassNames.Add(new Regex("Afx:ToolBar"));
            GetTopMenuItems();
            Trace.WriteLine(String.Format("Top level menu items are: {0}", String.Join(",", _topmenuitems.ToArray())));
        }

        private void GetTopMenuItems()
        {
            List<Ranorex.RawText> rawtextitems = _menubarelement.Find("descendant::rawtext").Select(e => new Ranorex.RawText(e)).ToList();
            _topmenuitems = rawtextitems.Select(r => r.RawTextValue.Trim().ToLower()).ToList();
        }

        private int GetIndexOf(List<String> list, String item)
        {
            for (int counter = 0; counter < list.Count(); counter++)
            {
                if (list[counter].Equals(item, StringComparison.InvariantCultureIgnoreCase)) return counter;
            }
            throw new Exception(String.Format("Item {0} was not found", item));
        }

        private List<String> GetSubMenuItems()
        {
            Ranorex.Form submenuform = Ranorex.Host.Local.FindSingle(CSubMenuWindow);
            //get items from top
            List<Ranorex.RawText> rawtextitems = submenuform.Find("descendant::rawtext").Select(e => new Ranorex.RawText(e)).ToList();
            List<String> topitems = rawtextitems.Select(r => r.RawTextValue.Trim().ToLower()).ToList();
            //get items from bottom
            Ranorex.Keyboard.Press(System.Windows.Forms.Keys.Up);
            rawtextitems = submenuform.Find("descendant::rawtext").Select(e => new Ranorex.RawText(e)).ToList();
            List<String> bottomitems = rawtextitems.Select(r => r.RawTextValue.Trim().ToLower()).ToList();
            //return to top
            Ranorex.Keyboard.Press(System.Windows.Forms.Keys.Down);
            //collate lists and parse
            List<String> allitems = new List<string>();
            allitems.AddRange(topitems);
            allitems.AddRange(bottomitems);
            ParseCapturedItems(ref allitems);
            Trace.WriteLine(String.Format("Sub menu items are: {0}", String.Join(",", allitems.ToArray())));
            return allitems;
        }

        private void ParseCapturedItems(ref List<String> items)
        {
            //remove all "&" characters
            items = items.Select(i => i.Trim('&')).ToList();
            items = items.Select(i => i.Replace("&", "")).ToList();
            //remove all text with invalid length
            items = items.Where(i => i.Length > 3).ToList();
            //remove all "..." characters
            items = items.Select(i => i.Replace("...", "")).ToList();
            //remove all text containing "ctrl+"
            items = items.Where(i => !i.Contains("ctrl+")).ToList();
            //remove all text containing "atl+"
            items = items.Where(i => !i.Contains("alt+")).ToList();
            //remove all duplicates
            items = items.Distinct().ToList();
        }


        public void SelectItem(String itempath, MenuSelectionModifier modifier = MenuSelectionModifier.None)
        {
            //get items from path
            Trace.WriteLine(String.Format("Selecting menu item {0}", itempath));
            var items = itempath.Split('~').Where(i => !String.IsNullOrEmpty(i)).Select(i => i.Trim().ToLower()).ToList();
            String key = String.Join("~", items.ToArray());
            if (items.Count() == 0) throw new Exception("No menu items found in path");

            //setup
            _form.Focus();
            _form.EnsureVisible();
            _menubarcontainer.Focus();
            _menubarcontainer.EnsureVisible();

            //select top menu item
            var topindex = GetIndexOf(_topmenuitems, items[0]);
            Ranorex.Keyboard.Press("{LMenu}");
            Ranorex.Keyboard.Press("{" + String.Format("right {0}", topindex) + "}");
            Ranorex.Keyboard.Press("{Return}");

            //select any sub menu items
            for (int counter = 1; counter < items.Count(); counter++)
            {
                //capture text
                var captureditems = GetSubMenuItems();
                //get index
                var index = GetIndexOf(captureditems, items[counter]);
                //navigate
                if (index > 0)
                {
                    Ranorex.Keyboard.Press("{" + String.Format("down {0}", index) + "}");
                }
                //check if need to select or expand
                if (counter == (items.Count() - 1))
                {
                    switch (modifier)
                    {
                        case MenuSelectionModifier.None:
                            Ranorex.Keyboard.Press(System.Windows.Forms.Keys.Enter);
                            break;
                        case MenuSelectionModifier.Ctrl:
                            Ranorex.Keyboard.Down(System.Windows.Forms.Keys.Control);
                            Ranorex.Keyboard.Press(System.Windows.Forms.Keys.Enter);
                            Ranorex.Keyboard.Up(System.Windows.Forms.Keys.Control);
                            break;
                        case MenuSelectionModifier.CtrlShift:
                            Ranorex.Keyboard.Down(System.Windows.Forms.Keys.LShiftKey);
                            Ranorex.Keyboard.Down(System.Windows.Forms.Keys.Control);
                            Ranorex.Keyboard.Press(System.Windows.Forms.Keys.Enter);
                            Ranorex.Keyboard.Up(System.Windows.Forms.Keys.LShiftKey);
                            Ranorex.Keyboard.Up(System.Windows.Forms.Keys.Control);
                            break;
                        case MenuSelectionModifier.Shift:
                            Ranorex.Keyboard.Down(System.Windows.Forms.Keys.LShiftKey);
                            Ranorex.Keyboard.Press(System.Windows.Forms.Keys.Enter);
                            Ranorex.Keyboard.Up(System.Windows.Forms.Keys.LShiftKey);
                            break;
                        default:
                            throw new Exception("Unknown menu selection modifier");
                    }

                }
                else
                {
                    Ranorex.Keyboard.Press(System.Windows.Forms.Keys.Right);
                }
            }


        }

    }


}
